//this is an extension of a Print Stream designed to intercept print calls  and send them somewhere else
// this can optionally block the calls from their destination altogether if desired

//import only what is needed
import java.io.PrintStream;
import java.io.OutputStream;
import java.util.Locale;

public class InterceptStream extends PrintStream {
	
	//define class instance vars
	private boolean blockcalls;
	//define constants
	
	//define constructor
	public InterceptStream(OutputStream outdest, boolean block) {
		
		//call ancestor
		super(outdest);
		//define if we should block the print calls from reaching their destination
		this.blockcalls = block;
		
	}
	
	//define overridden methods
	//PrintStream 	append(char c)
	//Appends the specified character to this output stream.
	public PrintStream append(char c) {
		//System.out.println("InterceptStream: append(" + c + ") called before it was defined...");
		return super.append(c);
	}
	//PrintStream 	append(CharSequence csq)
	//Appends the specified character sequence to this output stream.
	public PrintStream append(CharSequence csq) {
		//System.out.println("InterceptStream: append(" + csq + ") called before it was defined...");
		return super.append(csq);
	}
	//PrintStream 	append(CharSequence csq, int start, int end)
	//Appends a subsequence of the specified character sequence to this output stream.
	public PrintStream append(CharSequence csq, int start, int end) {
		//System.out.println("InterceptStream: append(" + csq + ", " + start + ", " + end + ") called before it was defined...");
		return super.append(csq,start,end);
	}
	//boolean 	checkError()
	//Flushes the stream and checks its error state.
	public boolean checkError() {
		//System.out.println("InterceptStream: checkError() called before it was defined...");
		return super.checkError();
	}
	//protected  void 	clearError()
	//Clears the internal error state of this stream.
	protected void clearError() {
		//System.out.println("InterceptStream: clearError() called before it was defined...");
		super.clearError();
	}
	//void 	close()
	//Closes the stream.
	public void close() {
		//System.out.println("InterceptStream: close() called before it was defined...");
		super.close();
	}
	//void 	flush()
	//Flushes the stream.
	public void flush() {
		//System.out.println("InterceptStream: flush() called before it was defined...");
		super.flush();
	}
	//PrintStream 	format(Locale l, String format, Object... args)
	//Writes a formatted string to this output stream using the specified format string and arguments.
	public PrintStream format(Locale l, String format, Object... args) {
		//System.out.println("InterceptStream: format(" + l + ", " + format + ", " + args + ") called before it was defined...");
		return super.format(l,format,args);
	}
	//PrintStream 	format(String format, Object... args)
	//Writes a formatted string to this output stream using the specified format string and arguments.
	public PrintStream format(String format, Object... args) {
		//System.out.println("InterceptStream: format(" + format + ", " + args + ") called before it was defined...");
		return super.format(format,args);
	}
	//void 	print(boolean b)
	//Prints a boolean value.
	public void print(boolean b) {
		//System.out.println("InterceptStream: print(" + b + ") called before it was defined...");
		super.print(b);
	}
	//void 	print(char c)
	//Prints a character.
	public void print(char c) {
		//System.out.println("InterceptStream: print(" + c + ") called before it was defined...");
		super.print(c);
	}
	//void 	print(char[] s)
	//Prints an array of characters.
	public void print(char[] s) {
		//System.out.println("InterceptStream: print(" + s + ") called before it was defined...");
		super.print(s);
	}
	//void 	print(double d)
	//Prints a double-precision floating-point number.
	public void print(double d) {
		//System.out.println("InterceptStream: print(" + d + ") called before it was defined...");
		super.print(d);
	}
	//void 	print(float f)
	//Prints a floating-point number.
	public void print(float f) {
		//System.out.println("InterceptStream: print(" + f + ") called before it was defined...");
		super.print(f);
	}
	//void 	print(int i)
	//Prints an integer.
	public void print(int i) {
		//System.out.println("InterceptStream: print(" + i + ") called before it was defined...");
		super.print(i);
	}
	//void 	print(long l)
	//Prints a long integer.
	public void print(long l) {
		//System.out.println("InterceptStream: print(" + l + ") called before it was defined...");
		super.print(l);
	}
	//void 	print(Object obj)
	//Prints an object.
	public void print(Object obj) {
		//System.out.println("InterceptStream: print(" + obj + ") called before it was defined...");
		super.print(obj);
	}
	//void 	print(String s)
	//Prints a string.
	public void print(String s) {
		//System.out.println("InterceptStream: print(" + s + ") called before it was defined...");
		super.print(s);
	}
	//PrintStream 	printf(Locale l, String format, Object... args)
	//A convenience method to write a formatted string to this output stream using the specified format string and arguments.
	public PrintStream printf(Locale l, String format, Object... args) {
		//System.out.println("InterceptStream: print(" + l + ", " + format + ", " + args + ") called before it was defined...");
		return super.printf(l,format,args);
	}
	//PrintStream 	printf(String format, Object... args)
	//A convenience method to write a formatted string to this output stream using the specified format string and arguments.
	public PrintStream printf(String format, Object... args) {
		//System.out.println("InterceptStream: print(" + format + ", " + args + ") called before it was defined...");
		return super.printf(format,args);
	}
	//void 	println()
	//Terminates the current line by writing the line separator string.
	public void println() {
		//System.out.println("InterceptStream: println() called before it was defined...");
		super.println();
	}
	//void 	println(boolean x)
	//Prints a boolean and then terminate the line.
	public void println(boolean x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(char x)
	//Prints a character and then terminate the line.
	public void println(char x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(char[] x)
	//Prints an array of characters and then terminate the line.
	public void println(char[] x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(double x)
	//Prints a double and then terminate the line.
	public void println(double x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(float x)
	//Prints a float and then terminate the line.
	public void println(float x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(int x)
	//Prints an integer and then terminate the line.
	public void println(int x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(long x)
	//Prints a long and then terminate the line.
	public void println(long x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(Object x)
	//Prints an Object and then terminate the line.
	public void println(Object x) {
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		super.println(x);
	}
	//void 	println(String x)
	//Prints a String and then terminate the line.
	public void println(String x) {
		
		//System.out.println("InterceptStream: println(" + x + ") called before it was defined...");
		
		//don't do anything if the String is null or empty
		if (x == null || x.isEmpty()){
			return;
		}
		
		//check for control header
		boolean header = false;
		if (x.substring(0,1).equals("$")){
			header = true;
		}
		
		//if there is a header, check for the control type
		//...who to send the message to??
		// if there is no header, send only to external console
		// 0 = none
		// 1 = external only
		// 2 = internal only
		// 3 = external and internal
		// anything else = external only
		boolean toexternal = false;
		boolean tointernal = false;
		if (x.length() > 2 && header){
			if (x.substring(1,2).equals("0")){
				//both false by default
			}else if (x.substring(1,2).equals("1")){
				toexternal = true;
			}else if (x.substring(1,2).equals("2")){
				tointernal = true;
			}else if (x.substring(1,2).equals("3")){
				toexternal = true;
				tointernal = true;
			}else{
				toexternal = true;
			}
			//strip off the header
			x = x.substring(2,x.length());
		}else{
			toexternal = true;
		}
		
		//send the message to the appropriate places
		if (!this.blockcalls && toexternal){
			super.println(x);
		}
		if (tointernal){
			//this is a println, so we should add a <br> tag
			x = x + "<br>";
			UIController.printConsole(x);
		}
		
	}
	//protected  void 	setError()
	//Sets the error state of the stream to true.
	protected void setError() {
		//System.out.println("InterceptStream: setError() called before it was defined...");
		super.setError();
	}
	//void 	write(byte[] buf, int off, int len)
	//Writes len bytes from the specified byte array starting at offset off to this stream.
	public void write(byte[] buf, int off, int len) {
		//System.out.println("InterceptStream: write(" + buf + ", " + off + ", " + len + ") called before it was defined...");
		super.write(buf,off,len);
	}
	//void 	write(int b)
	//Writes the specified byte to this stream.
	public void write(int b) {
		//System.out.println("InterceptStream: write(" + b + ") called before it was defined...");
		super.write(b);
	}
	
	
}